#pragma once
#include <Dynamics/force_module.h>
#include <Dynamics/Boundary/fixed_freedom_cpu.h>
#include <Dynamics/Damping/velocity_damping_cpu.h>
#include <Dynamics/ExtForce/gravity_cpu.h>

namespace PhysLeo
{

/**
 * integrator interface, all time integration method should implement this interface
 * contain some submodule like internal force module, fixed freedom moudle, damping module, external force module. call advanceTime to drive simulation.
 */
template<typename T>
class Integrator
{
public:
    /**
    * empty constructor
    */
    Integrator() = default;

    /**
    * delete default copy constructor
    */
    Integrator(const Integrator<T>&) = delete;

    /**
    * delete default move constructor
    */
    Integrator(Integrator<T>&&) = delete;

    /**
    * delete default copy assignment function
    */
    Integrator<T>& operator=(const Integrator<T>&) = delete;

    /**
    * delete default move assignment function
    */
    Integrator<T>& operator=(Integrator<T>&&) = delete;

    /**
    * virtual destructor
    */
    virtual ~Integrator() = default;

    /**
     * allocate resource for integrator and its submodule
     * @param[in] simData  simulation data
     */
    virtual void allocateResource(SimData<T>& simData)
    {
        if (internal_force_ != nullptr)internal_force_->allocateResource(simData);
        if (fixed_freedom_ != nullptr)fixed_freedom_->allocateResource(simData);
        if (velocity_damping_ != nullptr)velocity_damping_->allocateResource(simData);
        if (gravity_ != nullptr)gravity_->allocateResource(simData);
    }

    /**
     * advance simulation by timestep dt
     * @param[in] dt  timestep
     */
    virtual void advanceTime(float dt) = 0;

    /**
     * internal force module
     */
    std::shared_ptr<ForceModule<T>> internal_force_;

    /**
     * fixed freedom module
     */
    std::shared_ptr<FixedFreedomCpu<T>> fixed_freedom_;

    /**
     * damping module
     */
    std::shared_ptr<VelocityDampingCpu<T>> velocity_damping_;

    /**
     * gravity module
     */
    std::shared_ptr<GravityCpu<T>> gravity_;
};

}